#include "../header/bib_Cache.h"

extern struct stCACHE memCache[TAM_CACHE];
extern char usarCache;
sem_t accesoCache;

//Prototipos
void aumentarContadores();
int obtenerPosicionSector(uint32_t sector);
int obtenerPosicionLibre();


//Coloca todos los espacios como libre
void inicializarCache(){
	int i;

	if (usarCache!='S')
		return;

	for(i=0;i<TAM_CACHE; i++){
		memCache[i].libre=RESP_TRUE;
	}

	imprimirLogNumerico(DEBUG,"Cache Inicializada, tamaño:",TAM_CACHE);
}

//Actualiza un sector en cache o busca un espacio para copiarlo
void escribirEnCache(uint32_t sector, char *contenido){
	int posicion;

	if (usarCache!='S')
		return;

	sem_wait(&accesoCache);

	//Aumentar en 1 todos los contadores
	aumentarContadores();

	//Buscar si ya existe, si es asi, reinicializar contador y salir
	posicion=obtenerPosicionSector(sector);
	if (posicion < 0){
		//Si no existe, buscar el que tenga el contador mas alto o el primero libre
		posicion=obtenerPosicionLibre();
	}

	//Escribir en la posición
	memcpy(memCache[posicion].contenido,contenido,TAM_SECTOR);
	memCache[posicion].contadorUso=1;
	memCache[posicion].libre=0;
	memCache[posicion].sector=sector;

	sem_post(&accesoCache);

	imprimirLogNumerico(DEBUG,"Se escribio la cache en la posición:",posicion);
}

int leerDeCache(uint32_t sector, char *contenido){
	int posicion;

	if (usarCache!='S')
		return RESP_FALSE;

	sem_wait(&accesoCache);

	//Buscar si se encuentra el sector
	posicion=obtenerPosicionSector(sector);
	if (posicion >=0){
		//Si se encuentra

		//Copiar a la salida
		memcpy(contenido,memCache[posicion].contenido,TAM_SECTOR);

		//Aumentar en 1 todos los contadores
		aumentarContadores();

		//Reiniciar contador del sector leido
		memCache[posicion].contadorUso=1;

		sem_post(&accesoCache);

		imprimirLogNumerico(DEBUG,"Se leyo de la cache en la posición:",posicion);

		return RESP_TRUE;
	}

	sem_post(&accesoCache);

	imprimirLogNumerico(DEBUG,"Sector no encontrado en la cache:",(int)sector);

	return RESP_FALSE;
}

//Aumenta los contadores de todos los registros en 1
void aumentarContadores(){
	int i;

	for(i=0;i<TAM_CACHE; i++){
		if (memCache[i].contadorUso<255)
			memCache[i].contadorUso=memCache[i].contadorUso+1;
	}
}

//Devuelve la posicion del sector, sino se encuentra devuelve (-1)
int obtenerPosicionSector(uint32_t sector){
	int i;

	for(i=0;i<TAM_CACHE;i++){
		if (!(memCache[i].libre) && (memCache[i].sector==sector))
			return i;
	}

	//No se encontro
	return (-1);
}

//Busca una posición libre o una ocupada con el contador mas alto (LRU)
int obtenerPosicionLibre(){
	int i;
	int maximo=0;
	int posMax;

	for(i=0;i<TAM_CACHE;i++){
		if (memCache[i].libre)
			return i;
		else{
			if (memCache[i].contadorUso > maximo){
				posMax=i;
				maximo=memCache[i].contadorUso;
			}
		}
	}

	//No se encontro, devolver la posición menos recientemente usada
	return posMax;
}
